package com.sqi.algorithm.structure;

import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.Stack;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * 两个栈实现一个队列，支持多线程
 *
 * @Author sqi
 * @Date 2021/6/10
 * @Version V1.0.0
 **/
public class AsyncQueueTest {
    public static void main(String[] args) throws InterruptedException {
        int max = 2000000;
        Random random = new Random();
        List<Integer> putList = new ArrayList<Integer>(max);
        List<Integer> tackList = new ArrayList<Integer>(max);
        AsyncQueue queue = new AsyncQueue();
        CountDownLatch countDownLatch = new CountDownLatch(2);
        new Thread(() -> {
            for (int i = 0; i < max; i++) {
                int v = random.nextInt(max);
                queue.put(v);
                putList.add(v);
            }
            countDownLatch.countDown();
        }).start();
        new Thread(() -> {
            for (int i = 0; i < max; ) {
                Integer value = queue.take();
                if (value != null) {
                    tackList.add(value);
                    i++;
                }
            }
            countDownLatch.countDown();
        }).start();
        countDownLatch.await();
        System.out.println("Init Done:" + putList.size() + "===" + tackList.size());
        for (int i = 0; i < putList.size(); i++) {
            if (!putList.get(i).equals(tackList.get(i))) {
                System.out.println("FAIL");
            }
        }
    }

    static class AsyncQueue {
        final Stack<Integer> s1 = new Stack<Integer>();
        final Stack<Integer> s2 = new Stack<Integer>();
        final Object l1 = new Object();

        public void put(Integer value) {
            synchronized (l1) {
                s1.push(value);
            }
        }

        public Integer take() {
            if (s1.isEmpty() && s2.isEmpty()) {
                return null;
            }
            if (s2.isEmpty()) {
                synchronized (l1) {
                    while (!s1.isEmpty()) {
                        s2.push(s1.pop());
                    }
                }
            }
            return s2.pop();
        }
    }
}
